﻿namespace Homework20
{
    /// <summary>
    /// 四则运算
    /// </summary>
    internal class Program
    {
        static void Main(string[] args)
        {
            //提示用户输入
            Console.WriteLine("请输入一个四则运算表达式: ");

            //读取用户输入
            string expression = Console.ReadLine();

            //调用已构造的函数计算
            double result = EvaluateExpression(expression);

            //输出运算结果
            Console.WriteLine($"计算结果: {result}");
        }
        static double EvaluateExpression(string expression)
        {
            //用于存储操作数的栈
            Stack<double> operandStack = new Stack<double>();

            //用于存储运算符的栈
            Stack<char> operatorStack = new Stack<char>();

            //遍历表达式的每个字符
            for (int i = 0; i < expression.Length; i++)
            {
                char c = expression[i];

                //如果字符是数字或小数点，则处理数字（包括小数）
                if (char.IsDigit(c) || c == '.')
                {
                    // 处理数字，包括小数
                    double num = 0;
                    int decimalPlaces = 0;

                    //继续读取字符直到不再是数字或小数点
                    while (i < expression.Length && (char.IsDigit(expression[i]) || expression[i] == '.'))
                    {
                        if (expression[i] == '.')
                        {
                            decimalPlaces++;
                        }
                        else
                        {
                            num = num * 10 + (expression[i] - '0');
                            if (decimalPlaces > 0)
                            {
                                num /= Math.Pow(10, decimalPlaces);
                            }
                        }

                        //提前递增i，因为内部while循环也需要读取字符
                        i++;
                    }

                    //由于for循环末尾还会递增i，需要回退一个位置
                    i--; 

                    //将解析的数字压入操作数栈
                    operandStack.Push(num);
                }

                //如果字符是运算符
                else if (IsOperator(c))
                {
                    //当栈运算符的优先级大于等于当前运算符的优先级时，执行栈顶运算符对应的操作
                    while (operatorStack.Count > 0 && Precedence(operatorStack.Peek()) >= Precedence(c))
                    {
                        PerformOperation(operandStack, operatorStack);
                    }

                    //将当前运算符压入运算符栈
                    operatorStack.Push(c);
                }

                //如果字符是左括号
                else if (c == '(')
                {
                    //将左括号压入运算符栈
                    operatorStack.Push(c);
                }

                //如果字符是右括号
                else if (c == ')')
                {
                    //当栈顶不是左括号时，执行栈顶运算符对应的操作，直到遇到左括号
                    while (operatorStack.Count > 0 && operatorStack.Peek() != '(')
                    {
                        PerformOperation(operandStack, operatorStack);
                    }
                    if (operatorStack.Count > 0 && operatorStack.Peek() == '(')
                    {
                        //弹出左括号
                        operatorStack.Pop(); // 弹出左括号
                    }
                }
            }

            //当表达式遍历完后，执行栈中剩余的所有运算符
            while (operatorStack.Count > 0)
            {
                PerformOperation(operandStack, operatorStack);
            }

            //返回操作数栈中剩下的唯一值，即计算结果
            return operandStack.Pop();
        }

        static bool IsOperator(char c)
        {
            //判断字符是否为运算符
            return c == '+' || c == '-' || c == '*' || c == '/';
        }

        static int Precedence(char op)
        {
            //返回运算符的优先级（+、-优先级为1，*、/优先级为2）
            switch (op)
            {
                case '+':
                case '-':
                    return 1;
                case '*':
                case '/':
                    return 2;
                default:
                    return 0;
            }
        }

        static void PerformOperation(Stack<double> operandStack, Stack<char> operatorStack)
        {
            //如果操作数栈中的元素少于2个或运算符栈为空，则抛出异常
            if (operandStack.Count < 2 || operatorStack.Count == 0)
            {
                throw new InvalidOperationException("Invalid expression");
            }

            double b = operandStack.Pop();
            double a = operandStack.Pop();
            char op = operatorStack.Pop();

            //根据运算符执行相应的操作，并将结果压回操作数栈
            switch (op)
            {
                case '+':
                    operandStack.Push(a + b);
                    break;
                case '-':
                    operandStack.Push(a - b);
                    break;
                case '*':
                    operandStack.Push(a * b);
                    break;
                case '/':
                    if (b == 0)
                    {
                        throw new DivideByZeroException("Division by zero");
                    }
                    operandStack.Push(a / b);
                    break;
            }
        }
    }
}
